/*
 * Copyright (C), 2013-2015, 韩伟
 * FileName: ScheduleServiceImpl.java
 * Author:   yyt
 * Date:     2015年5月8日 下午1:36:15
 * Description: //模块目的、功能描述      
 * History: //修改记录
 * <author>      <time>      <version>    <desc>
 * 修改人姓名             修改时间            版本号                  描述
 */
package com.cango.qutz.web.job.impl;

import com.cango.framework.base.dao.BaseDaoImpl;
import com.cango.framework.base.job.JobExecute;
import com.cango.framework.base.job.QuartzJobFactory;
import com.cango.framework.base.pagination.PageInfo;
import com.cango.framework.base.pagination.PaginationResult;
import com.cango.qutz.web.entity.ScheduleExecution;
import com.cango.qutz.web.entity.ScheduleJob;
import com.cango.qutz.web.entity.ScheduleParam;
import com.cango.qutz.web.job.IScheduleService;
import com.cango.qutz.web.util.DateUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * 〈一句话功能简述〉<br>
 * 〈功能详细描述〉
 *
 * @author yyt
 * @see [相关类/方法]（可选）
 * @since [产品/模块版本] （可选）
 */
@Service("scheduleService")
public class ScheduleServiceImpl extends BaseDaoImpl implements IScheduleService {
    private final Log log = LogFactory.getLog(ScheduleServiceImpl.class);
    /** 任务sql的命名空间 */
    private static final String SQL_NAMESPACE = "job.";

    /**
     * 新增任 务的sql的ID
     */
    private static final String SQL_QUERY_COUNT_BY_NAME = "queryCountByName";

    /**
     * 新增任 务的sql的ID
     */
    private static final String SQL_INSERT_JOB = "insertJob";

    /**
     * 查询所有任务的sql的ID
     */
    private static final String SQL_QUERY_ALL_JOBS = "queryAllJobs";

    /**
     * 分页查询任务的sql的ID
     */
    private static final String SQL_QUERY_JOBS_BY_PAGE = "queryJobsByPage";

    /**
     * 更新任务时间间隔
     */
    private static final String SQL_UPDATE_JOB_CRON = "updateJobCron";

    /**
     * 更新任务状态
     */
    private static final String SQL_UPDATE_JOB_STATUS = "updateJobStatus";

    /**
     * 查询任务信息
     */
    private static final String SQL_QUERY_JOB_BY_PARAMS = "queryJobByparams";

    /**
     * 删除任务信息
     */
    private static final String SQL_DELETE_JOB = "deleteJob";

    /**
     * schedulerFactoryBean
     */
    @Autowired
    private SchedulerFactoryBean schedulerFactoryBean;


    @Override
    public List<ScheduleJob> queryAllJob() {
        return queryList(SQL_NAMESPACE + SQL_QUERY_ALL_JOBS, "");
    }

    @Override
    public void initAllJob() throws SchedulerException {
        Scheduler scheduler = schedulerFactoryBean.getScheduler();
        List<ScheduleJob> jobList = this.queryAllSchedule();
        for (ScheduleJob job : jobList) {
            TriggerKey triggerKey = TriggerKey.triggerKey(job.getJobName(), job.getJobGroup());
            CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
            if(null != trigger){
                JobKey jobkey=new JobKey(job.getJobName(),job.getJobGroup());
                scheduler.deleteJob(jobkey);
                trigger=null;
            }
            // 判断是否存在 若不存在就新建 存在就更新他的时间
            if (null == trigger) {
                JobDetail jobDetail = (JobDetail) JobBuilder.newJob(QuartzJobFactory.class)
                        .withIdentity(job.getJobName(), job.getJobGroup()).build();
                jobDetail.getJobDataMap().put("quartzScheduler", job);
                jobDetail.getJobDataMap().put("myJob", new JobExecute());

                // 表达式调度构建器，启动quartz时不做第一次调度
                CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression())
                        .withMisfireHandlingInstructionDoNothing();

                // 按新的cronExpression表达式构建一个新的trigger
                trigger = TriggerBuilder.newTrigger()
                        .withSchedule(scheduleBuilder).withIdentity(job.getJobName(), job.getJobGroup())
                        .build();

                scheduler.scheduleJob(jobDetail, trigger);

                if ("0".equals(job.getJobStatus())) {
                    JobKey jobKey = JobKey.jobKey(job.getJobName(), job.getJobGroup());
                    scheduler.pauseJob(jobKey);
                }

            } else {
                // Trigger已存在，那么更新相应的定时设置
                // 表达式调度构建器
                CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression())
                        .withMisfireHandlingInstructionDoNothing();

                // 按新的cronExpression表达式重新构建trigger
                trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();

                JobKey jobkey=new JobKey(job.getJobName(),job.getJobGroup());
                //更新job数据
                JobDetail jobDetail= scheduler.getJobDetail(jobkey);
                jobDetail.getJobDataMap().remove("quartzScheduler");
                jobDetail.getJobDataMap().put("quartzScheduler", job);
                // 按新的trigger重新设置job执行
                scheduler.rescheduleJob(triggerKey, trigger);
                if ("0".equals(job.getJobStatus())) {
                    JobKey jobKey = JobKey.jobKey(job.getJobName(), job.getJobGroup());
                    scheduler.pauseJob(jobKey);
                }
            }
        }

    }

    @Override
    public void updateJobCron(ScheduleJob job) {
        update(SQL_NAMESPACE + SQL_UPDATE_JOB_CRON, job);
    }

    @Override
    public void updateJobStatus(ScheduleJob job) {
        update(SQL_NAMESPACE + SQL_UPDATE_JOB_STATUS, job);
    }

    @Override
    public PaginationResult<ScheduleJob> getJobList(ScheduleJob param, PageInfo pageinfo) throws SchedulerException {
        return queryListByPage(SQL_NAMESPACE + SQL_QUERY_JOBS_BY_PAGE, param, pageinfo);
    }

    @Override
    public String insertJob(ScheduleJob job) {
        try {
            // 表达式调度构建器
            CronScheduleBuilder.cronSchedule(job.getCronExpression());
        } catch (Throwable e) {
            return "errCron";
        }
        //设置jobName和jobGroup
        Map<String,Object> param = new HashMap<String,Object>();
        param.put("jobId", job.getJobId());
        ScheduleJob sj = queryForObject("job.query_jobDefines_byJobId",param);
        job.setJobName(sj.getJobName()+ DateUtils.formatDate(new Date(), "yyyyMMddHHmmss"));
        job.setJobGroup(sj.getJobGroup());
        job.setJobStatus("0");
        insert(SQL_NAMESPACE + SQL_INSERT_JOB, job);
        return null;
    }

    @Override
    public boolean validJobName(String jobName) {
        int count = queryForObject(SQL_NAMESPACE + SQL_QUERY_COUNT_BY_NAME, jobName);
        return count <= 0;
    }

    @Override
    public void updateDoStartJob(ScheduleJob param) throws SchedulerException {
        Scheduler scheduler = schedulerFactoryBean.getScheduler();
        ScheduleJob factJob=getScheduleById(param.getScheduleId());
        TriggerKey triggerKey = TriggerKey.triggerKey(factJob.getJobName(), factJob.getJobGroup());
        CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
        // 判断是否存在 若不存在就新建 存在就启动
        if (null == trigger) {
            this.createJob(factJob);
        } else {
            JobKey jobKey = JobKey.jobKey(factJob.getJobName(), factJob.getJobGroup());

            //更新job数据
            JobDetail jobDetail= scheduler.getJobDetail(jobKey);
            jobDetail.getJobDataMap().remove("quartzScheduler");
            jobDetail.getJobDataMap().put("quartzScheduler", factJob);
            scheduler.resumeJob(jobKey);
        }
        param.setJobStatus("1");
        this.updateJobStatus(param);
    }

    /**
     * 功能描述: <br>
     * 创建新的任务方法
     *
     * @param job 任务参数
     * @throws SchedulerException 异常
     * @see [相关类/方法](可选)
     * @since [产品/模块版本](可选)
     */
    public void createJob(ScheduleJob job) throws SchedulerException {
        Scheduler scheduler = schedulerFactoryBean.getScheduler();
        JobDetail jobDetail = JobBuilder.newJob(QuartzJobFactory.class)
                .withIdentity(job.getJobName(), job.getJobGroup()).build();

        jobDetail.getJobDataMap().put("quartzScheduler", job);
        jobDetail.getJobDataMap().put("myJob", new JobExecute());

        // 表达式调度构建器
        CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression()).withMisfireHandlingInstructionDoNothing();

        // 按新的cronExpression表达式构建一个新的trigger
        CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(job.getJobName(), job.getJobGroup())
                .withSchedule(scheduleBuilder).build();

        scheduler.scheduleJob(jobDetail, trigger);
    }

    /**
     * 功能描述: <br>
     * 查询任务信息
     *
     * @param job 任务条件
     * @return 任务具体信息
     * @see [相关类/方法](可选)
     * @since [产品/模块版本](可选)
     */
    @Override
    public ScheduleJob queryJobByParams(ScheduleJob job) {
        return queryForObject(SQL_NAMESPACE + SQL_QUERY_JOB_BY_PARAMS, job);
    }

    @Override
    public String editJob(ScheduleJob job) throws SchedulerException {
        Scheduler scheduler = schedulerFactoryBean.getScheduler();
        ScheduleJob factJob=getScheduleById(job.getScheduleId());
        JobKey jobKey = JobKey.jobKey(factJob.getJobName(), factJob.getJobGroup());
        factJob.setCronExpression(job.getCronExpression());
        factJob.setMailTo(job.getMailTo());
        TriggerKey triggerKey = TriggerKey.triggerKey(factJob.getJobName(), factJob.getJobGroup());
        //CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
        CronTrigger trigger = null;

        String status ="";
        if(scheduler.checkExists(triggerKey)){
        //if (null != trigger) {
            Trigger.TriggerState triggerState = scheduler.getTriggerState(triggerKey);
            status = triggerState.name();

            CronScheduleBuilder scheduleBuilder = null;
            try {
                scheduleBuilder = CronScheduleBuilder.cronSchedule(factJob.getCronExpression()).withMisfireHandlingInstructionDoNothing();
            } catch (Throwable e) {
                log.error("编辑任务调度发生错误",e);
                return "errCron";
            }

            // 按新的cronExpression表达式重新构建trigger
            trigger = TriggerBuilder.newTrigger().withIdentity(factJob.getJobName(), factJob.getJobGroup())
                    .withSchedule(scheduleBuilder).build();
            // 按新的trigger重新设置job执行
            scheduler.rescheduleJob(triggerKey, trigger);

            // 判断之前的任务状态 如果是暂停 则重新暂停该任务
            if ("PAUSED".equals(status)) {
                scheduler.pauseJob(jobKey);
            }

        }
        //先删除，再创建
      /*  scheduler.deleteJob(jobKey);
        createJob(factJob);
        if ("PAUSED".equals(status)) {
            scheduler.pauseJob(jobKey);
        }*/
        // 更新任务时间间隔
        this.updateJobCron(factJob);
        return null;
    }

    @Override
    public void deleteJob(ScheduleJob job) throws SchedulerException {
        Scheduler scheduler = schedulerFactoryBean.getScheduler();
        //scheduleId
        ScheduleJob factJob=getScheduleById(job.getScheduleId());
        JobKey jobKey = JobKey.jobKey(factJob.getJobName(), factJob.getJobGroup());
        TriggerKey triggerKey = TriggerKey.triggerKey(factJob.getJobName(), factJob.getJobGroup());
        scheduler.unscheduleJob(triggerKey);
        scheduler.deleteJob(jobKey);
        delete(SQL_NAMESPACE + SQL_DELETE_JOB, job);
    }

    @Override
    public void updateDoStopJob(ScheduleJob job) throws SchedulerException {
        Scheduler scheduler = schedulerFactoryBean.getScheduler();
        ScheduleJob factJob=getScheduleById(job.getScheduleId());
        JobKey jobKey = JobKey.jobKey(factJob.getJobName(), factJob.getJobGroup());
        scheduler.pauseJob(jobKey);
        //清除job的dubbo缓存
        job.setJobStatus("0");
        updateJobStatus(job);
    }

    private ScheduleJob getScheduleById(Integer scheduleId){
        return queryForObject("job.queryScheduleById",scheduleId);
    }
    private List<ScheduleJob> queryAllSchedule(){
        return queryList(SQL_NAMESPACE + "queryAllSchedule", null);
    }
    @Override
    public String insertJobAndParam(ScheduleJob job, Map<String, Object> param) {
        String returncode= insertJob(job);
        if(null != returncode){
            return returncode;
        }
        Map<String,Object> pv = null;
        if(null != param && !param.isEmpty()){
            Set<String> keys=param.keySet();
            for(String key : keys){
                pv = new HashMap<String , Object>();
                pv.put("scheduleId",job.getScheduleId());
                pv.put("paramId",key);
                pv.put("paramValue", param.get(key));
                insert("job.insertScheduleParam",pv);
            }
        }
        return null;
    }

    @Override
    public int insertExecution(ScheduleExecution execution) {
        return insert("job.insertExecution",execution);
    }

    @Override
    public List<ScheduleParam> queryParamsBySchedule(Integer scheduleId) {
        return queryList("job.query_paramSet_ByScheduleId",scheduleId);
    }

    @Override
    public void updateJobOnce(ScheduleJob job) {
        Scheduler scheduler = schedulerFactoryBean.getScheduler();
        JobKey jobKey=new JobKey(job.getJobName(),job.getJobGroup());
        try {
            JobDataMap jdm=new JobDataMap();
            jdm.put("executeType","2");
            scheduler.triggerJob(jobKey,jdm);
        } catch (SchedulerException e) {
            log.error("任务立即执行遇到错误",e);
        }
    }

    @Override
    public List<ScheduleExecution> getExecutionsBySid(Integer scheduleId) {
        return queryList("job.getExeutionListBySid",scheduleId);
    }

    @Override
    public ScheduleJob getScheduleInfoBySid(Integer scheduleId) {
        return queryForObject("job.queryScheduleById",scheduleId);
    }
}
